import socket
import asyncio
import threading
import functools

from utils import logging
from handler import BaseHandler


class TCPServer(object):

    def __init__(self, server_address: tuple, handler_cls):
        self.server_address = server_address
        self.handler_cls = handler_cls

        self.__socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.__socket.bind(self.server_address)
        self.__socket.listen(5)
        self.__loop: asyncio.AbstractEventLoop = asyncio.get_event_loop()

        # 用于睡眠线程
        self.th_event = threading.Event()

        # 是否关闭状态
        self.__is_shutdown: bool = True

        # 客户端列表, 存在字典里 key 是客户端地址, value 是对应的客户端 handler 实例
        self.client_list: dict = {}

        # 发送列表
        self.send_list: list = []

    def run_server(self):
        self.th_event.clear()
        self.__is_shutdown = False

        try:
            threading.Thread(target=lambda: self.__loop.run_until_complete(self.__run())).start()
        except Exception:
            pass

    async def __run(self):

        logging.info("服务器运行在 {}:{}".format(self.server_address[0], self.server_address[1]))

        while not self.__is_shutdown:
            client, remote_address = await self.__loop.sock_accept(self.__socket)
            self.__loop.create_task(self.on_connection(client, remote_address))

    async def on_connection(self, client: socket.socket, remote_address: tuple):
        handler: BaseHandler = self.handler_cls(self, client, remote_address)

        self.client_list["%s:%d" % (remote_address[0], remote_address[1])] = handler

        while handler.is_connection:
            try:
                data: bytes = await self.__loop.sock_recv(client, handler.recv_len)
            except ConnectionResetError:
                """
                异常处理, ConnectionResetError 远程主机主动断开连接
                该异常是对方主动与我方断开连接, 
                """

                handler.on_connect_err('ConnectionResetError', descriotion="远程主机主动断开连接")

                break

            except ConnectionAbortedError:
                """
                异常处理, ConnectionAbortedError 你的主机中软件终止了一个已建立的连接
                该异常是我方主动与对方断开连接, 
                """

                handler.on_connect_err('ConnectionAbortedError', descriotion="你的主机中软件终止了一个已建立的连接")

                break

            except:
                """
                异常处理, 奇奇怪怪的异常处理,
                该异常处理其他异常
                """
                handler.on_connect_err('OtherError', descriotion="异常处理, 奇奇怪怪的异常处理")

                return None, True

            handler.on_message(data)

        return False

    def send(self, data_type:str, data: str, target = None):
        """
        发送消息

        :param data_type:
        :param data:
        :param target:
        :return:
        """

        # 先判断目标是不是空, 是空为广播
        if target is None:
            for key in list(self.client_list):
                client: BaseHandler = self.client_list[key]

                try:
                    client.send(data_type, data)
                except Exception:
                    client.close_connnect()
                    del self.client_list[key]

        # 指定目标就发送给指定客户端
        else:
            client = self.client_list[target]

            try:
                client.send(data_type, data)
            except Exception:
                del self.client_list[target]

    def on_disconnection(self, remote_address: tuple):
        logging.error("Lost connection.")
        del self.client_list["%s:%d" % (remote_address[0], remote_address[1])]

    def close(self):
        self.__is_shutdown = True
        self.th_event.wait()
        self.client_list.clear()

    @property
    def is_run(self):
        return not self.__is_shutdown


class SimpeHandler(BaseHandler):

    def handle(self, data_type, data):
        logging.info(
            "Received {host}: {data}".format(host="%s:%d" % (self.remote_address[0], self.remote_address[1]),
                                             data=data))

if __name__ == '__main__':
    server = TCPServer(server_address=("127.0.0.1", 8080), handler_cls=SimpeHandler)
    server.run_server()

    while server.is_run:
        data = input()

        if data == "show client":
            print(server.client_list)
        elif data[:13] == "select client":
            key = data[13:].strip()
            try:
                client = server.client_list[key]
            except KeyError:
                logging.error("No corresponding D was found.")
                continue
            server.send_list.append(client)
            logging.info("Selected client %s." % key)
        elif data[:13] == "show selected":
            print(server.send_list)
        elif data[:9] == "send data":
            pkt = data[9:].strip()
            _type, content = pkt.split(":")
            if len(server.send_list) <= 0:
                logging.error("Send list to be empty")
            for client in server.send_list:
                client.send(_type, content)

            logging.info("Sended.")
        elif data == "exit":
            server.close()
            break
